//给你一个 m x n 的矩阵 board ，由若干字符 'X' 和 'O' ，找到所有被 'X' 围绕的区域，并将这些区域里所有的 'O' 用 'X' 填充
//。
//
//
//
//
// 示例 1：
//
//
//输入：board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O",
//"X","X"]]
//输出：[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]]
//解释：被围绕的区间不会存在于边界上，换句话说，任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上，或不与边界上的 'O' 相连的 'O' 最终都
//会被填充为 'X'。如果两个元素在水平或垂直方向相邻，则称它们是“相连”的。
//
//
// 示例 2：
//
//
//输入：board = [["X"]]
//输出：[["X"]]
//
//
//
//
// 提示：
//
//
// m == board.length
// n == board[i].length
// 1 <= m, n <= 200
// board[i][j] 为 'X' 或 'O'
//
//
//
// Related Topics 深度优先搜索 广度优先搜索 并查集 数组 矩阵 👍 785 👎 0

package leetcode.editor.cn;

@SuppressWarnings("all")
//Java：被围绕的区域
public class 被围绕的区域 {
    public static void main(String[] args) {
        Solution solution = new 被围绕的区域().new Solution();
        // TO TEST
        char[][] board = {
                {'X', 'X', 'X', 'X'},
                {'X', 'O', 'O', 'X'},
                {'X', 'X', 'O', 'X'},
                {'X', 'O', 'X', 'X'}
        };

        solution.solve(board);
    }


    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        int[] p;
        int m;
        int n;

        int find(int x) {
            while (x != p[x]) {
                p[x] = p[p[x]];
                x = p[x];
            }
            return x;
        }

        boolean isConnected(int a, int b) {
            return find(a) == find(b);
        }

        void union(int a, int b) {
            int pa = find(a);
            int pb = find(b);
            if (pa != pb) {
                p[pa] = pb;
            }
        }

        void init(int size) {

            p = new int[size];
            for (int i = 0; i < p.length; i++) {
                p[i] = i;
            }
        }

        int node(int i, int j) {
            return i * n + j;
        }

        public void solve(char[][] board) {
            m = board.length;
            n = board[0].length;
            int PRESENT = m * n;
            init(PRESENT + 1);

            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    if (i == 0 || i == m - 1 || j == 0 || j == n - 1) {
                        if (board[i][j] == 'O') {
                            union(node(i, j), PRESENT);
                        }
                    } else {
                        if (board[i][j] == 'O') {
                            if (board[i - 1][j] == 'O') {
                                union(node(i, j), node(i - 1, j));
                            }
                            if (board[i + 1][j] == 'O') {
                                union(node(i, j), node(i + 1, j));
                            }
                            if (board[i][j - 1] == 'O') {
                                union(node(i, j), node(i, j - 1));
                            }
                            if (board[i][j + 1] == 'O') {
                                union(node(i, j), node(i, j + 1));
                            }
                        }
                    }
                }

            }

            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    if (board[i][j] == 'O' && !isConnected(node(i, j), PRESENT)) {
                        board[i][j] = 'X';
                    }
                }
            }


        }
//leetcode submit region end(Prohibit modification and deletion)

    }
}
